package net.lucamasini.ricette.server;

import static net.lucamasini.ricette.server.EntityManagerFactoryListener.jpaTemplateInContext;

import java.util.*;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

import net.lucamasini.ricette.model.*;

import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.JpaTemplate;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class RicetteServiceServlet extends RemoteServiceServlet {

	private final static Logger LOG = Logger.getLogger(RicetteServiceServlet.class.getName()); 
	
	private static final long serialVersionUID = 1L;

	public Ricetta findRicetta(String key) {
		JpaTemplate template = jpaTemplateInContext(getServletContext());

		return template.find(Ricetta.class, key);
	}

	@SuppressWarnings("unchecked")
	public List<Ingrediente> findAllIngredienti() {
		try {
			JpaTemplate template = jpaTemplateInContext(getServletContext());
			
			return template.executeFind(new JpaCallback<List<Ingrediente>>() {

				@Override
				public List<Ingrediente> doInJpa(EntityManager em)
						throws PersistenceException {

					return new ArrayList<Ingrediente>(em.createQuery("select i from Ingrediente i order by i.descrizione").getResultList());
				}
			});

		} catch (Exception e) {
			throw new RuntimeException(e);
		}	
	}

	@SuppressWarnings("unchecked")
	public List<TipoIngrediente> findAllTipoIngredienti() {
		try {
			JpaTemplate template = jpaTemplateInContext(getServletContext());
			
			return template.executeFind(new JpaCallback<List<TipoIngrediente>>() {

				@Override
				public List<TipoIngrediente> doInJpa(EntityManager em)
						throws PersistenceException {

					return new ArrayList<TipoIngrediente>(em.createQuery("select i from TipoIngrediente i order by i.descrizione").getResultList());
				}
			});

		} catch (Exception e) {
			throw new RuntimeException(e);
		}	
	}

	public void salvaIngrediente(Ingrediente ingrediente, String keyTI) {
		JpaTemplate template = jpaTemplateInContext(getServletContext());

		TipoIngrediente ti = template.find(TipoIngrediente.class, keyTI);
		ingrediente.setKeyTipoIngrediente(ti.getId());
		
		template.merge(ingrediente);
	}
	
	@SuppressWarnings("unchecked")
	public List<Ricetta> findAllRicette() {
		try {
			JpaTemplate template = jpaTemplateInContext(getServletContext());
			
			return template.executeFind(new JpaCallback<List<Ricetta>>() {

				@Override
				public List<Ricetta> doInJpa(EntityManager em)
						throws PersistenceException {

					final List<Ricetta> resultList = em.createQuery("select r from Ricetta r order by r.titolo").getResultList();
					
					final ArrayList<Ricetta> retVal = new ArrayList<Ricetta>(resultList.size());
					for(Ricetta r: resultList) {
						Ricetta newR = new Ricetta();
						newR.setId(r.getId());
						newR.setVersion(r.getVersion());
						newR.setDescrizione(r.getDescrizione());
						List<IngredientiRicetta> newIRA = new ArrayList<IngredientiRicetta>();
						for(IngredientiRicetta newIr: r.getIngredientiRicetta()) {
							newIRA.add(newIr);
						}
						newR.setIngredientiRicetta(newIRA);
						newR.setTitolo(r.getTitolo());
						newR.setTempoPreparazione(r.getTempoPreparazione());
						newR.setDifficolta(r.getDifficolta());
						newR.setPersone(r.getPersone());
						retVal.add(newR);
					}
					return retVal;
				}
			});

		} catch (Exception e) {
			throw new RuntimeException(e);
		}	
	}

	public void salvaRicetta(final Ricetta ricetta, final List<IngredientiRicetta> irCollection) {
		ricetta.setIngredientiRicetta(irCollection);
		JpaTemplate template = jpaTemplateInContext(getServletContext());

		template.execute(new JpaCallback<Void>() {

			@Override
			public Void doInJpa(EntityManager em)
					throws PersistenceException {

				em.merge(ricetta);
				if( ricetta.getId()!=null ) {
					Ricetta oldRicetta = em.find(Ricetta.class, ricetta.getId());
					
					Set<String> validKeys = new HashSet<String>();
					
					for(IngredientiRicetta ir: ricetta.getIngredientiRicetta()) {
						validKeys.add(ir.getId());
					}

					for(IngredientiRicetta ir: oldRicetta.getIngredientiRicetta()) {
						if( !validKeys.contains(ir.getId())) {
							em.remove(ir);
						}
					}					
				}

				return null;
			}
		});

		LOG.info("Ricetta dopo merge/persist");
		printRicetta(ricetta);
	}

	private void printRicetta(final Ricetta ricetta) {
		JpaTemplate template = jpaTemplateInContext(getServletContext());

		template.execute(new JpaCallback<Void>() {

			@Override
			public Void doInJpa(EntityManager em)
					throws PersistenceException {

				Ricetta newRicetta = em.find(Ricetta.class, ricetta.getId());
				
				LOG.info("Ricetta: "+newRicetta.getId());
				for(IngredientiRicetta ir: newRicetta.getIngredientiRicetta()){
					LOG.info("IngredientiRicetta: "+ir.getId());
					if( ir.getKeyIngrediente()!=null ){ 
						LOG.info("Ingrediente: "+ir.getKeyIngrediente());
					}
				}
				
				return null;
			}
		});
		
	}

	public void salvaTipoIngrediente(TipoIngrediente tipoIngrediente) {
		JpaTemplate template = jpaTemplateInContext(getServletContext());

		template.merge(tipoIngrediente);
	}

	public void deleteTipoIngrediente(TipoIngrediente ti) {
		cancellaEntita(TipoIngrediente.class.getSimpleName(), ti.getId());
	}

	public void remove(Ricetta ricetta) {
		cancellaEntita(Ricetta.class.getSimpleName(), ricetta.getId());
	}
	
	public void cancellaIngrediente(Ingrediente i) {
		cancellaEntita(Ingrediente.class.getSimpleName(), i.getId());
	}
	
	public void cancellaEntita(final String entita, final String key) {
		JpaTemplate template = jpaTemplateInContext(getServletContext());
		
		template.execute(new JpaCallback<Void>() {

			@Override
			public Void doInJpa(EntityManager em)
					throws PersistenceException {
					
				em.createQuery("delete from "+entita+" e where e.id = :id").setParameter("id", key).executeUpdate();
				
				return null;
			}
		});		
	}
}
